package net.oschina.git.fsppp.utils;

import net.oschina.git.fsppp.exception.P3Exception;
import net.oschina.git.fsppp.model.P3Block;
import net.oschina.git.fsppp.model.P3Dir;
import net.oschina.git.fsppp.model.P3Disk;
import net.oschina.git.fsppp.model.P3FAT;

import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by guin_guo on 2016/10/9.
 */
public class P3Utils {
    public static final String basePath = System.getProperty("user.dir") + "\\src\\main\\resources\\";
    public static final String SUFFIX_OF_DISK = ".disk";
    public static final int MAX_BLOCK_SIZE = 64;
    /**
     * 将源字节数组src 从 begin 开始，复制 长度 length 到目标字节数组 dist
     * @param src
     * @param dist
     * @param srcBegin
     * @param srcLength
     * @return
     */
    public static Byte[] copyByte(Byte[] src, Byte[] dist, int srcBegin, int srcLength,int distBegin) {
        int j = distBegin;
        for (int i = srcBegin;i<srcLength;i++) {
            dist[j++] = new Byte(src[i]);
        }
        return dist;
    }

    /**
     * 写磁盘
     * @param disk
     * @return
     * @throws Exception
     */
    public static P3Disk write2DiskFile(P3Disk disk) throws Exception {
        File file = new File(basePath+ "\\" + disk.getName() + SUFFIX_OF_DISK);
        if (file.exists()) {
            FileOutputStream diskFile = new FileOutputStream(file);
            for (P3Block block :disk.getBlocks()) {
                byte[] blockContent = block.tobyte();
                diskFile.write(blockContent);
            }
            diskFile.close();
            return disk;
        }
        return null;
    }

    /**
     * 获取磁盘文件分配表
     * @param name
     * @return
     * @throws Exception
     */
    public static P3FAT getFatByDisk(String name) throws Exception {
        File file = new File(basePath+ "\\" + name.toLowerCase() + SUFFIX_OF_DISK);
        if (file.exists()) {
            FileInputStream diskFile = new FileInputStream(file);
            byte[] b = new byte[128];
            diskFile.read(b);
            P3FAT fat = new P3FAT();
            fat.setDisk(name.toUpperCase());
            fat.setContent(byte2Byte(b));
            diskFile.close();
            return fat;
        }
        return null;

    }

    /**
     * byte[] 2 Byte[]
     * @param src
     * @return
     */
    public static Byte[] byte2Byte(byte[] src) {
        Byte[] dist = new Byte[src.length];
        for (int i = 0; i < src.length; i++) {
            dist[i] = src[i];
        }
        return dist;
    }
    /**
     * Byte[] 2 byte[]
     * @param src
     * @return
     */
    public static byte[] Byte2byte(Byte[] src) {
        byte[] dist = new byte[src.length];
        for (int i = 0; i < src.length; i++) {
            dist[i] = src[i];
        }
        return dist;
    }

    /**
     * 根据磁盘名称跟block id 获取P3Dir list
     * @param diskName
     * @param root
     * @return
     * @throws Exception
     */
    public static List<P3Dir> getByDiskNameAndBlockIds(String diskName, List<Integer> root) throws Exception {
        File file = new File(basePath+ "\\" + diskName.toLowerCase() + SUFFIX_OF_DISK);
        if (file.exists()) {
            List<P3Dir> l = new ArrayList<>();
            FileInputStream diskFile = new FileInputStream(file);
            byte[] in = new byte[MAX_BLOCK_SIZE];
            byte[] diskBytes = new byte[8192];
            diskFile.read(diskBytes, 0, 8192);
            for (Integer id : root) {
//                diskFile.read(in, id * MAX_BLOCK_SIZE, MAX_BLOCK_SIZE);
                int k = 0;
                for (int i = MAX_BLOCK_SIZE * id; i < MAX_BLOCK_SIZE * id + MAX_BLOCK_SIZE; i++) {
                    in[k++] = diskBytes[i];
                }
                if (in[1] == P3Dir.TYPE_OF_DIR) {//文件夹
                    byte[] path = new byte[MAX_BLOCK_SIZE];//路径
                    int j = 0;//path index
                    int i = 3;//b index
                    while (in[i] != -1) {//路径结尾是-1
                        path[j++] = in[i];
                        i++;
                    }
                    Byte[] truePath = new Byte[j];
                    P3Utils.copyByte(P3Utils.byte2Byte(path), truePath, 0, j, 0);
                    String dirPath = new String(P3Utils.Byte2byte(truePath));
                    P3Dir dir = new P3Dir();
                    dir.setStartNum(id);
                    dir.setLength(1);
                    dir.setPath(dirPath);
                    dir.setName(dirPath.substring(dirPath.lastIndexOf("\\")+1));
                    dir.setType(in[1]);
                    dir.setPid(in[2]);
                    l.add(dir);
                }
            }
            diskFile.close();
            return l;
        }
        return null;
    }
    /**
     * 根据磁盘名称跟pid 获取当前目录下的 P3Dir list
     * @param diskName
     * @param pid
     * @return
     * @throws Exception
     */
    public static List<P3Dir> getByDiskNameAndPid(String diskName, Integer pid) throws Exception {
        P3FAT fat = P3Utils.getFatByDisk(diskName);
        File file = new File(basePath+ "\\" + diskName.toLowerCase() + SUFFIX_OF_DISK);
        if (file.exists()) {
            List<P3Dir> l = new ArrayList<>();
            List<LinkedList<Integer>> fileLinks = fat.toFileLinked();
            List<Integer> ids = new ArrayList<>(fileLinks.size());
            fileLinks.stream().filter(v -> v.size() == 1).forEach(v -> ids.add(v.get(0)));//过滤出文件（夹）
            FileInputStream diskFile = new FileInputStream(file);
            byte[] diskBytes = new byte[8192];
            diskFile.read(diskBytes, 0, 8192);
            diskFile.close();
            for (Integer id : ids) {
                byte[] in = new byte[MAX_BLOCK_SIZE];
                int k = 0;
                for (int i = MAX_BLOCK_SIZE * id; i < MAX_BLOCK_SIZE * id + MAX_BLOCK_SIZE; i++) {
                    if (k == 0 && diskBytes[i+2] != pid.byteValue()) {
                        break;
                    }
                    in[k++] = diskBytes[i];
                }
                if (in[0] != 0) {
                    P3Dir dir = byte2Dir(in);
                    l.add(dir);
                }
            }
            return l;
        }
        return null;
    }

    /**
     *  根据磁盘名称跟pid 获取当前目录下的 目录和文件
     * @param diskName
     * @param pid
     * @return
     * @throws Exception
     */
    public static List<P3Dir> getAllByDiskNameAndPid(String diskName, Integer pid) throws Exception {
        P3FAT fat = P3Utils.getFatByDisk(diskName);
        File file = new File(basePath+ "\\" + diskName.toLowerCase() + SUFFIX_OF_DISK);
        if (file.exists()) {
            List<P3Dir> l = new ArrayList<>();
            List<LinkedList<Integer>> fileLinks = fat.toFileLinked();
            FileInputStream diskFile = new FileInputStream(file);
            byte[] diskBytes = new byte[8192];
            diskFile.read(diskBytes, 0, 8192);
            diskFile.close();
            for (LinkedList<Integer> linkedList : fileLinks) {
                if (diskBytes[MAX_BLOCK_SIZE*linkedList.get(0)+2] == pid) { //这个目录下的才处理
                    if (diskBytes[linkedList.get(0) * MAX_BLOCK_SIZE + 1] == P3Dir.TYPE_OF_FILE) {                            //文件
                        int id = linkedList.get(0);
                        byte[] in = new byte[MAX_BLOCK_SIZE * linkedList.size()];
                        in[0] = (byte) id;                                   //block id
                        in[1] = P3Dir.TYPE_OF_FILE;                         //file
                        in[2] = (byte) pid.intValue();                      //pid
                        int j = MAX_BLOCK_SIZE * id + 3;                        //path index
                        int i = 3;//b index
                        while (i < MAX_BLOCK_SIZE && (diskBytes[j] != -1)) {                    //continue copy path
                            in[i++] = diskBytes[j++];
                        }
                        in[i++] = diskBytes[j++];
                        for (int k = 1; k < linkedList.size(); k++) {                           //continue copy content
                            id = linkedList.get(k);
                            for (int b = MAX_BLOCK_SIZE * id + 3; b < MAX_BLOCK_SIZE * id + MAX_BLOCK_SIZE; b++) {
                                if (diskBytes[b] == -1) {
                                    break;
                                }
                                in[i++] = diskBytes[b];
                            }
                        }
                        in[i] = -1;
                        if (in[0] != 0) {
                            P3Dir dir = byte2Dir(in);
                            l.add(dir);
                        }

                    } else {//目录
                        byte[] in = new byte[MAX_BLOCK_SIZE];
                        int id = linkedList.get(0);
                        int k = 0;
                        for (int i = MAX_BLOCK_SIZE * id; i < MAX_BLOCK_SIZE * id + MAX_BLOCK_SIZE; i++) {
                            in[k++] = diskBytes[i];
                        }
                        if (in[0] != 0) {
                            P3Dir dir = byte2Dir(in);
                            l.add(dir);
                        }
                    }
                }
                
            }
            return l;
        }
        return null;
    }

    /**
     * 根据byte[] 返回Dir
     * @param in
     * @return
     */
    public static P3Dir byte2Dir(byte[] in) {
        P3Dir dir = new P3Dir();

        byte[] path = new byte[MAX_BLOCK_SIZE-1];//路径
        int j = 0;//path index
        int i = 3;//b index
        while (in[i] != -1) {//路径结尾是-1
            path[j++] = in[i++];
        }
        Byte[] truePath = new Byte[j];
        P3Utils.copyByte(P3Utils.byte2Byte(path), truePath, 0, j, 0);
        String dirPath = new String(P3Utils.Byte2byte(truePath));
        String name = dirPath.substring(dirPath.lastIndexOf("\\") + 1);
        dir.setName(name);
        dir.setStartNum(in[0]);
        dir.setPid(in[2]);
        dir.setType(in[1]);
        if (in[1] == P3Dir.TYPE_OF_DIR) {//文件夹
            dir.setLength(1);
            dir.setPath(dirPath);
        } else {
            //File
            dir.setPath(dirPath);
            dir.setAttr(name.contains(".") ? name.substring(name.lastIndexOf(".") + 1) : "");
            if (in.length - i > 0) {
                int length = (in.length - i) / (MAX_BLOCK_SIZE - 3) + 1;//总共用了多少块最后一块的最后一位是-1，所以保留
                dir.setLength(length);
                int ik = i + 1;
                for (; ik < in.length; ik++) {
                    if (in[ik] == -1) {
                        break;
                    }
                }
                Byte[] content = new Byte[ik - i - 1];//具体长度
                copyByte(byte2Byte(in), content, i + 1, ik, 0);
                dir.setContent(content);
            }
        }

        return dir;
    }

    /**
     * 删除目录
     * @param diskName 磁盘名
     * @param id block id
     * @throws Exception
     */
    public static void deleteDirById(String diskName, Integer id) throws Exception {
        File file = new File(basePath+ "\\" + diskName.toLowerCase() + SUFFIX_OF_DISK);
        if (file.exists()) {
            P3FAT fat = P3Utils.getFatByDisk(diskName);
            FileInputStream diskFile = new FileInputStream(file);
            byte[] diskBytes = new byte[8192];
            diskFile.read(diskBytes, 0, 8192);
            diskFile.close();
            // 释放内存
            for (int i=MAX_BLOCK_SIZE*id+1;i<MAX_BLOCK_SIZE*id+MAX_BLOCK_SIZE;i++) {
                diskBytes[i] = 0;
            }

            FileOutputStream diskFileOut = new FileOutputStream(file,false);

            //释放内存空间
            Integer[] ids = new Integer[1];
            ids[0] = id;
            fat.release(ids);
            //写fat
            byte[] fatContent = Byte2byte(fat.getContent());
            diskBytes = P3Utils.Byte2byte
                    (P3Utils.copyByte(P3Utils.byte2Byte(fatContent),
                            P3Utils.byte2Byte(diskBytes), 0, fatContent.length,0));

            //写回
            diskFileOut.write(diskBytes);
            diskFileOut.close();
        }

    }

    /**
     * 根据id，磁盘名 获取文件(夹)
     * @param diskName
     * @param id
     * @return
     * @throws Exception
     */
    public static P3Dir getById(String diskName, Integer id) throws Exception {
        File file = new File(basePath+ "\\" + diskName.toLowerCase() + SUFFIX_OF_DISK);
        if (file.exists()) {
            FileInputStream diskFile = new FileInputStream(file);
            P3Dir dir = getById(diskFile, id);
            diskFile.close();
            return dir;
        }
        return null;
    }

    /**
     * 根据id，文件流获取文件夹
     * @param inputStream
     * @param id
     * @return
     * @throws Exception
     */
    public static P3Dir getById(FileInputStream inputStream, Integer id) throws Exception {
        byte[] diskBytes = new byte[8192];
        inputStream.read(diskBytes, 0, 8192);
        byte[] in = new byte[MAX_BLOCK_SIZE];
        in = Byte2byte(
                copyByte(
                        byte2Byte(diskBytes), byte2Byte(in), id * MAX_BLOCK_SIZE, (id + 1) * MAX_BLOCK_SIZE, 0
                ));
        byte[] path = new byte[MAX_BLOCK_SIZE];//路径
        int j = 0;//path index
        int i = 3;//b index
        while (in[i] != -1) {//路径结尾是-1
            path[j++] = in[i];
            i++;
        }
        String dirPath = new String(path).trim();
        P3Dir dir = byte2Dir(in);//new P3Dir();
        if (in[1] == P3Dir.TYPE_OF_DIR) {//文件夹
            dir.setLength(1);
            return dir;
        } else if (in[1] == P3Dir.TYPE_OF_FILE) {//文件
            //1. 那fat 得到fileLink，再拿到当前文件的link
            //2. 根据这个link，跳转拿content
            P3FAT fat = getFatByDisk(dirPath.substring(0, 1));
            LinkedList<Integer> fileLink = new LinkedList<>();
            for (LinkedList<Integer> ll : fat.toFileLinked()) {
                if (ll.get(0) == dir.getStartNum()) {
                    fileLink = ll;
                    break;
                }
            }
            Byte[] content = new Byte[(fileLink.size() - 1) * (MAX_BLOCK_SIZE - 3)];
            int ct = 0;
            for (int k = 1;k<fileLink.size();k++) {
                int bid = fileLink.get(k);
                for (int bi = (MAX_BLOCK_SIZE * bid) + 3; bi < (MAX_BLOCK_SIZE * bid) + MAX_BLOCK_SIZE; bi++) {
                    if (diskBytes[bi] != -1) {
                        content[ct++] = diskBytes[bi];
                    } else break;
                }
            }
            Byte[] newContent = new Byte[ct];
            copyByte(content, newContent, 0, ct, 0);
            dir.setContent(newContent);
            dir.setLength(fileLink.size());
            return dir;
        }
        return null;
    }

    /**
     * 写磁盘
     * @param dir
     * @return
     * @throws Exception
     */
    public static P3Dir write2Disk(P3Dir dir,P3FAT fat) throws Exception {
        File file = new File(basePath+ "\\" + dir.getPath().substring(0,1) + SUFFIX_OF_DISK);
        if (file.exists()) {
            FileInputStream diskFileIn = new FileInputStream(file);
            //整盘读取
            byte[] diskBytes = new byte[8192];
            diskFileIn.read(diskBytes);
            diskFileIn.close();
            FileOutputStream diskFile = new FileOutputStream(file,false);
            //写dir
            Byte[] out = new Byte[MAX_BLOCK_SIZE];
            out[0] = Byte.parseByte(dir.getStartNum() + "");
            out[1] = (byte)dir.getType();
            out[2] = Byte.parseByte(dir.getPid() + "");
            byte[] path = dir.getPath().getBytes();
            P3Utils.copyByte(byte2Byte(path), out, 0, path.length,3);
            out[path.length + 3] = -1;//end
            for (int i = path.length + 4; i < MAX_BLOCK_SIZE; i++) {
                out[i] = 0;
            }

            //写fat
            byte[] fatContent = Byte2byte(fat.getContent());
            diskBytes = P3Utils.Byte2byte
                    (P3Utils.copyByte(P3Utils.byte2Byte(fatContent),
                                      P3Utils.byte2Byte(diskBytes), 0, fatContent.length,0));

            //修改制定位置
            for (int i = MAX_BLOCK_SIZE * dir.getStartNum(),j=0; i < MAX_BLOCK_SIZE * dir.getStartNum()+out.length; i++) {
                diskBytes[i] = out[j++];
            }
            //写回
            diskFile.write(diskBytes);
            diskFile.close();
            return dir;
        }
        return null;
    }

    /**
     * 根据路径获取文件(夹)
     * @param path
     * @return
     * @throws Exception
     */
    public static P3Dir getByPath(String path) throws Exception {
        if (path.split("\\\\").length == 1) {
            return getRootByPath(path);
        }
        String diskName = path.substring(0, 1);
        File file = new File(basePath+ "\\" + diskName + SUFFIX_OF_DISK);
        if (file.exists()) {
            P3FAT fat = getFatByDisk(diskName);
            List<Integer> dirLinks = fat.toDirLinked();
            List<P3Dir> dirs = P3Utils.getByDiskNameAndBlockIds(diskName, dirLinks);
            dirs.add(getRootByPath(diskName + ":\\"));
            P3Dir parent = null;
            for (P3Dir dir : dirs) {
                if (dir.getType() == P3Dir.TYPE_OF_DIR) {//文件夹
                    String dirPath = dir.getPath();
                    if (dirPath.equals(path) || (dirPath + "\\").equals(path)) {
                        return dir;
                    }
                    String subPath = path.substring(0, path.lastIndexOf("\\") + 1);
                    if (dirPath.equals(subPath) || dirPath.equals(subPath.substring(0, subPath.length()-1))) {
                        parent = dir;
                    }
                }
            }
            if (parent != null) {
                List<P3Dir> fileAndDirs = P3Utils.getAllByDiskNameAndPid(path.substring(0, 1), parent.getStartNum());
                for (P3Dir dir : fileAndDirs) {
                    if (dir.getType() == P3Dir.TYPE_OF_FILE && dir.getPath().equals(path)) {//文件
                        return dir;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 根据路径获取文件（夹）
     * @param path
     * @return
     * @throws Exception
     */
    public static List<P3Dir> listAllDirs(String path) throws Exception {
        String diskName = path.substring(0, 1);
        File file = new File(basePath+ "\\" + diskName + SUFFIX_OF_DISK);
        if (file.exists()) {
            P3Dir dir = getByPath(path);
            if (dir == null) {
                return null;
            }
            List<P3Dir> dirs = getAllByDiskNameAndPid(diskName, dir.getStartNum());
            return dirs;
        }
        return null;
    }

    /**
     * 创建文件
     * @param parent
     * @param name
     * @param content
     * @return
     * @throws Exception
     */
    public static P3Dir createDirFile(P3Dir parent, String name, Byte[] content) throws Exception {
        String diskName = parent.getPath().substring(0, 1);
        P3FAT fat = getFatByDisk(diskName);
        P3Dir dir = new P3Dir();
        dir.setPid(parent.getStartNum());
        dir.setName(name);
        dir.setType(P3Dir.TYPE_OF_FILE);
        if (name.contains(".")) {
            dir.setAttr(name.substring(name.lastIndexOf(".") + 1));
        } else {
            dir.setAttr("");
        }
        dir.setStartNum(fat.allocate());
        dir.setPath(parent.getPath() + (parent.getPath().endsWith("\\")?"":"\\") + name);
        if (content != null) {
            dir.setContent(content);
        } else {
            dir.setLength(1);
        }
        dir = P3Utils.editFile(fat, dir);
        return dir;
    }

    /**
     * 增加，修改文件
     * @param fat
     * @param dir
     * @return
     * @throws Exception
     */
    private static P3Dir editFile(P3FAT fat, P3Dir dir) throws Exception {
        P3Dir dir1 = null;
        //增加
        //修改
        if (dir.getContent() != null) {
            dir1 = P3Utils.write2DiskWithContent(dir, fat);
        } else {
            dir1 = P3Utils.write2Disk(dir, fat);
        }
        return dir1;
    }

    /**
     * 写文件进磁盘
     * @param dir
     * @param fat
     * @return
     * @throws Exception
     */
    private static P3Dir write2DiskWithContent(P3Dir dir, P3FAT fat) throws Exception {
        File file = new File(basePath+ "\\" + dir.getPath().substring(0,1) + SUFFIX_OF_DISK);
        if (file.exists()) {
            FileInputStream diskFileIn = new FileInputStream(file);
            //整盘读取
            byte[] diskBytes = new byte[8192];
            diskFileIn.read(diskBytes);
            diskFileIn.close();
            FileOutputStream diskFile = new FileOutputStream(file,false);
            //写dir
            Byte[] out = new Byte[MAX_BLOCK_SIZE];
            out[0] = Byte.parseByte(dir.getStartNum() + "");
            out[1] = (byte)dir.getType();
            out[2] = Byte.parseByte(dir.getPid() + "");
            byte[] path = dir.getPath().getBytes();
            out = P3Utils.copyByte(byte2Byte(path), out, 0, path.length,3);
            if (out[1] == P3Dir.TYPE_OF_FILE) {
                out[path.length + 3] = -1;//end
                Byte[] content = dir.getContent();
                int c = 0;
                for (int i = path.length + 4; i < MAX_BLOCK_SIZE; i++) {
                    out[i] = 0;
                }
                //int conut = (content.length - c) % (MAX_BLOCK_SIZE - 3) == 0 ? (content.length - c) / (MAX_BLOCK_SIZE - 3) : (content.length - c) / (MAX_BLOCK_SIZE - 3) + 1;
                int count = content.length / (MAX_BLOCK_SIZE - 3) + 1; //总共用了多少块最后一块的最后一位是-1，所以保留
                int pid = dir.getStartNum();
                /**
                 * 写Block
                 */
                for (int bi = 0;bi<count;bi++) {
                    int id = fat.allocate();
                    int begin = id * MAX_BLOCK_SIZE;
                    diskBytes[begin] = (byte)id;
                    diskBytes[begin+1] = P3Dir.TYPE_OF_FILE;
                    diskBytes[begin+2] = (byte)pid;
                    if (bi != count - 1) {
                        for (int i = begin + 3; i < begin + MAX_BLOCK_SIZE ; i++) {
                            diskBytes[i] = content[c++];
                        }
                    } else {
                        int i = begin + 3;
                        for (; (i < begin + content.length % (MAX_BLOCK_SIZE - 3)) && content[c] != -1; i++) {
                            diskBytes[i] = content[c++];
                        }
                        diskBytes[i] = -1;
                    }
                    pid = id;
                }
            }

            //写fat
            byte[] fatContent = Byte2byte(fat.getContent());
            diskBytes = P3Utils.Byte2byte
                    (P3Utils.copyByte(P3Utils.byte2Byte(fatContent),
                            P3Utils.byte2Byte(diskBytes), 0, fatContent.length,0));

            //修改制定位置
            for (int i = MAX_BLOCK_SIZE * dir.getStartNum(),j=0; i < MAX_BLOCK_SIZE * dir.getStartNum()+out.length; i++) {
                diskBytes[i] = out[j++];
            }
            //写回
            diskFile.write(diskBytes);
            diskFile.close();
            return dir;
        }
        return null;
    }

    public static P3Dir editPath(P3Dir dir) throws Exception {
        File file = new File(basePath+ "\\" + dir.getPath().substring(0,1) + SUFFIX_OF_DISK);
        if (file.exists()) {
            FileInputStream diskFileIn = new FileInputStream(file);
            //整盘读取
            byte[] diskBytes = new byte[8192];
            diskFileIn.read(diskBytes);
            diskFileIn.close();
            int begin = dir.getStartNum() * MAX_BLOCK_SIZE;
            byte[] path = dir.getPath().getBytes();
            int j = 0;
            int i = begin + 3;
            for (; i < begin + 3 + path.length; i++) {
                diskBytes[i] = path[j++];
            }
            diskBytes[i++] = -1;
            for (; i < begin + MAX_BLOCK_SIZE; i++) {
                diskBytes[i] = 0;
            }
            FileOutputStream diskFile = new FileOutputStream(file, false);
            Byte[] dff = byte2Byte(diskBytes);
            diskFile.write(diskBytes);
            diskFile.close();
            //如果是目录，递归修改子文件 文件夹的路径
            if (dir.getType() == P3Dir.TYPE_OF_DIR) {
                List<P3Dir> childs = P3Utils.getAllByDiskNameAndPid(dir.getPath().substring(0, 1), dir.getStartNum());
                for (P3Dir child : childs) {
                    changeR(dff,dir, child);
                }
            }
            //再次写回
            diskFile = new FileOutputStream(file, false);
            diskBytes = Byte2byte(dff);
            diskFile.write(diskBytes);
            diskFile.close();
            return dir;
        }
        return dir;
    }

    private static void changeR(Byte[] diskBytes, P3Dir parent, P3Dir child) throws Exception {
        String newPath = parent.getPath() + "\\" + child.getName();
        child.setPath(newPath);
        byte[] path = newPath.getBytes();
        int j = 0;
        int begin = child.getStartNum() * MAX_BLOCK_SIZE ;
        int i = begin + 3;
        while ((i < begin + 3 + newPath.getBytes().length) && (i < begin + MAX_BLOCK_SIZE - 1)) {
            diskBytes[i++] = path[j++];
        }
        diskBytes[i++] = -1;
        while (i < begin + MAX_BLOCK_SIZE - 1) {
            diskBytes[i++] = 0;
        }
        if (child.getType() == P3Dir.TYPE_OF_DIR) {
            List<P3Dir> childs = P3Utils.getAllByDiskNameAndPid(parent.getPath().substring(0, 1), child.getStartNum());
            for (P3Dir c : childs) {
                changeR(diskBytes,parent, c);
            }
        }
    }

    public static void editContent(String diskName, P3Dir persist, P3Dir dir) throws Exception {
        File file = new File(basePath+ "\\" + dir.getPath().substring(0,1) + SUFFIX_OF_DISK);
        if (file.exists()) {
            P3FAT fat = getFatByDisk(diskName);
            FileInputStream diskFileIn = new FileInputStream(file);
            //整盘读取
            byte[] diskBytes = new byte[8192];
            diskFileIn.read(diskBytes);
            diskFileIn.close();
            LinkedList<Integer> ids = null;
            List<LinkedList<Integer>> fileLinks = fat.toFileLinked();
            for (LinkedList<Integer> ll : fileLinks) {
                if (ll.get(0) == dir.getStartNum()) {
                    ids = ll;
                    break;
                }
            }
            if (ids == null) {
                throw new P3Exception("[文件分配表异常]"+"文件不存在.");
            }
            int oldLength = persist.getContent().length / (MAX_BLOCK_SIZE - 3) + 1;
            int newLength = dir.getContent().length / (MAX_BLOCK_SIZE - 3) + 1;
            int diff = newLength - oldLength;
            int ct = 0;//index of content
            Byte[] content = dir.getContent();
            if (dir.getContent().length == 0) {
                diskBytes[dir.getStartNum()] = -1;
            }
            if (diff == 0) {
                if (ids.size() == 1) {
                    int aid = fat.allocate();
                    ids.add(aid);
                    diskBytes[aid * MAX_BLOCK_SIZE] = (byte) aid;
                    diskBytes[aid * MAX_BLOCK_SIZE + 1] = (byte) P3Dir.TYPE_OF_FILE;
                    diskBytes[aid * MAX_BLOCK_SIZE + 2] = (byte) dir.getStartNum();
                    diskBytes[dir.getStartNum()] = (byte) aid;
                    diskBytes[aid] = -1;
                }
                int i = 1;
                for (; i <= oldLength; i++) {
                    int id = ids.get(i);
                    int begin = id * MAX_BLOCK_SIZE;
                    int len = i != oldLength ? begin + MAX_BLOCK_SIZE : begin + content.length - ct + 3;
                    int j = begin + 3;
                    while (j < len) {
                        diskBytes[j++] = content[ct++];
                    }
                    if (i == oldLength) {
                        diskBytes[j++] = -1;
                        if (ct == 0) {
                            //没有写任何数据
                            diskBytes[id] = 0;
                            j = begin + 3;
                            while (j < begin + MAX_BLOCK_SIZE) {
                                diskBytes[j++] = 0;
                            }
                        }
                    }
                }
            } else {
                if (diff < 0) {
                    for (int i = 1; i <= newLength; i++) {
                        int id = ids.get(i);
                        int begin = MAX_BLOCK_SIZE * id;
                        int j = begin + 3;
                        int len = i != newLength ? begin + MAX_BLOCK_SIZE : begin + content.length - ct + 3;
                        while (j < len) {
                            diskBytes[j++] = content[ct++];
                        }
                        if (i == newLength) {
                            diskBytes[j++] = -1;
                            while (j < begin + MAX_BLOCK_SIZE) {
                                diskBytes[j++] = 0;
                            }
                            //修改fat
                            diskBytes[id] = -1;
                        }
                    }
                    if (ct == 0) {
                        //清空文件内容
                        diskBytes[ids.get(1)] = 0;
                    }
                    //释放内存
                    for (int i = newLength + 1; i <= oldLength; i++) {
                        int id = ids.get(i);
                        int begin = MAX_BLOCK_SIZE * id;
                        for (int k = begin; k < MAX_BLOCK_SIZE + begin; k++) {
                            diskBytes[k] = 0;
                        }
                        //修改fat
                        diskBytes[id] = 0;
                    }
                } else {
                    if (ids.size() == 1) {
                        int aid = fat.allocate();
                        ids.add(aid);
                        diskBytes[aid * MAX_BLOCK_SIZE] = (byte) aid;
                        diskBytes[aid * MAX_BLOCK_SIZE + 1] = (byte) P3Dir.TYPE_OF_FILE;
                        diskBytes[aid * MAX_BLOCK_SIZE + 2] = (byte) dir.getStartNum();
                        diskBytes[dir.getStartNum()] = (byte) aid;
                    }
                    for (int i = 1; i <= oldLength; i++) {
                        int id = ids.get(i);
                        int begin = MAX_BLOCK_SIZE * id;
                        int j = begin + 3;
                        int len = begin + MAX_BLOCK_SIZE;
                        while (j < len) {
                            diskBytes[j++] = content[ct++];
                        }
                    }
                    //需要请求新的内存块
                    int pid = ids.get(oldLength);
                    int id = 0;
                    for (int i = oldLength + 1; i <= newLength; i++) {
                        id = fat.allocate();
                        int begin = MAX_BLOCK_SIZE * id;
                        diskBytes[begin] = (byte)id;
                        diskBytes[begin + 1] = (byte) P3Dir.TYPE_OF_FILE;
                        diskBytes[begin + 2] = (byte) pid;
                        int j = begin + 3;
                        int len = i != newLength ? begin + MAX_BLOCK_SIZE : begin + content.length - ct + 3;
                        while (j < len) {
                            diskBytes[j++] = content[ct++];
                        }
                        //修改fat
                        diskBytes[pid] = (byte) id;
                        pid = id;
                        if (i == newLength) {
                            diskBytes[j] = -1;
                        }
                    }
                    if (id != 0) {
                        diskBytes[id] = -1;
                    }
                }
            }
            FileOutputStream diskFile = new FileOutputStream(file, false);
            diskFile.write(diskBytes);
            diskFile.close();
        }

    }

    public static void deleteFile(P3Dir persist) throws Exception {
        String diskName = persist.getPath().substring(0, 1);
        File file = new File(basePath + "\\" + diskName +SUFFIX_OF_DISK);
        if (file.exists()) {
            P3FAT fat = P3Utils.getFatByDisk(diskName);
            FileInputStream diskFile = new FileInputStream(file);
            byte[] diskBytes = new byte[8192];
            diskFile.read(diskBytes, 0, 8192);
            diskFile.close();
            List<LinkedList<Integer>> fileLinks = fat.toFileLinked();
            LinkedList<Integer> fileLink = null;
            for (LinkedList<Integer> ll : fileLinks) {
                if (ll.get(0) == persist.getStartNum()) {
                    fileLink = ll;
                    break;
                }
            }
            if (fileLink == null) {
                throw new P3Exception("文件分配表异常");
            }
            for (Integer id : fileLink) {
                int begin = id * MAX_BLOCK_SIZE + 1;
                //释放内存
                while ((diskBytes[begin] != -1) && (begin < id * MAX_BLOCK_SIZE + MAX_BLOCK_SIZE)) {
                    diskBytes[begin++] = 0;
                }
                diskBytes[begin] = 0;
                //修改文件分配表
                diskBytes[id] = 0;
            }
            FileOutputStream diskFileOut = new FileOutputStream(file, false);
            //写回
            diskFileOut.write(diskBytes);
            diskFileOut.close();
        }
    }

    public static P3Dir getRootByPath(String path) {
        if (path.split("\\\\").length == 1) {
            P3Dir dir = new P3Dir();
            dir.setName(path.split("\\\\")[0]);
            dir.setPath(path.split("\\\\")[0] + "\\");
            dir.setStartNum(0);
            dir.setPid(0);
            dir.setType(P3Dir.TYPE_OF_DIR);
            return dir;
        }
        return null;
    }

    /**
     * 返回该文件 文件夹 的文件分配链
     * 要么有，要么null
     * @param dir
     * @return
     */
    public static LinkedList<Integer> getFileLinks(P3Dir dir) {
        String diskName = dir.getPath().substring(0, 1);
        File file = new File(basePath + "\\" + diskName +SUFFIX_OF_DISK);
        try {
            if (file.exists()) {
                P3FAT fat = getFatByDisk(diskName);
                return fat.getFileLink(dir.getStartNum());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return null;
    }

    public static void deleteDir(P3Dir dir) throws Exception {
        String diskName = dir.getPath().substring(0, 1);
        List<P3Dir> childs = P3Utils.getAllByDiskNameAndPid(diskName, dir.getStartNum());
        for (P3Dir dir1 : childs) {
            if (dir1.getType() == P3Dir.TYPE_OF_FILE) {
                P3Utils.deleteFile(dir1);
            } else {
                P3Utils.deleteDir(dir1);
            }
            if (dir1.getType() == P3Dir.TYPE_OF_DIR) {
                P3Utils.deleteDirById(diskName,dir1.getStartNum());
            }
        }
        if (dir.getType() == P3Dir.TYPE_OF_DIR) {
            P3Utils.deleteDirById(diskName,dir.getStartNum());
        }
    }

    public static List<P3Dir> search(P3Dir current, String key) throws Exception {
        List<P3Dir> l = new ArrayList<>();
        List<P3Dir> dirs = getAllByDiskNameAndPid(current.getPath().substring(0, 1), current.getStartNum());
        for (P3Dir dir : dirs) {
            if (dir.getName().contains(key)) {
                l.add(dir);
            }
            if (dir.getType() == P3Dir.TYPE_OF_DIR) {
                traverseSearch(l, dir, key);
            }
        }
        return l;
    }

    public static void traverseSearch(List<P3Dir> l, P3Dir current, String key) throws Exception {
        List<P3Dir> dirs = getAllByDiskNameAndPid(current.getPath().substring(0, 1), current.getStartNum());
        for (P3Dir dir : dirs) {
            if (dir.getName().contains(key)) {
                l.add(dir);
            }
            if (dir.getType() == P3Dir.TYPE_OF_DIR) {
                traverseSearch(l, dir, key);
            }
        }
    }

}
